package org.zhuxian.cn.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.RedisConnectionFailureException;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.concurrent.TimeUnit;
import java.util.Set;
import java.util.stream.Collectors;

@Component
public class RedisUtils {
    private static final ObjectMapper objectMapper = new ObjectMapper();

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    // 基础键值操作
    public <T> void set(String key, T value) {
        try {
            stringRedisTemplate.opsForValue().set(key, objectMapper.writeValueAsString(value));
        } catch (Exception e) {
            throw new RuntimeException("Redis操作异常", e);
        }
    }

    public <T> T get(String key, Class<T> clazz) {
        try {
            String value = stringRedisTemplate.opsForValue().get(key);
            if (value == null) {
                return null;
            }
            return objectMapper.readValue(value, clazz);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("Redis数据反序列化失败", e);
        } catch (RedisConnectionFailureException e) {
            throw new RuntimeException("Redis连接异常", e);
        } catch (Exception e) {
            throw new RuntimeException("Redis操作异常", e);
        }
    }

    public <T> void setEx(String key, T value, long timeout, TimeUnit unit) {
        try {
            stringRedisTemplate.opsForValue().set(key, objectMapper.writeValueAsString(value), timeout, unit);
        } catch (Exception e) {
            throw new RuntimeException("Redis操作异常", e);
        }
    }

    // 哈希表操作
    public <T> void hPut(String key, String hashKey, T value) {
        try {
            stringRedisTemplate.opsForHash().put(key, hashKey, objectMapper.writeValueAsString(value));
        } catch (Exception e) {
            throw new RuntimeException("Redis操作异常", e);
        }
    }

    public <T> T hGet(String key, String hashKey, Class<T> clazz) {
        try {
            Object value = stringRedisTemplate.opsForHash().get(key, hashKey);
            return objectMapper.readValue(value.toString(), clazz);
        } catch (Exception e) {
            throw new RuntimeException("Redis操作异常", e);
        }
    }

    // 泛型安全方法
    public <T> T get(String key, TypeReference<T> typeReference) {
        try {
            String value = stringRedisTemplate.opsForValue().get(key);
            return objectMapper.readValue(value, typeReference);
        } catch (Exception e) {
            throw new RuntimeException("Redis操作异常", e);
        }
    }

    // 原子操作
    public Long increment(String key, long delta) {
        try {
            return stringRedisTemplate.opsForValue().increment(key, delta);
        } catch (Exception e) {
            throw new RuntimeException("Redis操作异常", e);
        }
    }

    // 集合操作
    public <T> Long add(String key, T value) {
        try {
            return stringRedisTemplate.opsForSet().add(key, objectMapper.writeValueAsString(value));
        } catch (Exception e) {
            throw new RuntimeException("Redis操作异常", e);
        }
    }

    public <T> Set<T> members(String key, Class<T> clazz) {
        try {
            Set<String> values = stringRedisTemplate.opsForSet().members(key);
            return values.stream()
                    .map(v -> {
                        try {
                            return objectMapper.readValue(v, clazz);
                        } catch (Exception e) {
                            throw new RuntimeException("反序列化失败", e);
                        }
                    })
                    .collect(Collectors.toSet());
        } catch (Exception e) {
            throw new RuntimeException("Redis操作异常", e);
        }
    }

    public <T> Long remove(String key) {
        try {
            return stringRedisTemplate.opsForSet().remove(key);
        } catch (Exception e) {
            throw new RuntimeException("Redis操作异常", e);
        }
    }
}
